package common;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class Utils {
    //声明WebDriver变量，用于管理浏览器驱动
    public static WebDriver driver;

    //初始化浏览器驱动的方法，支持传入浏览器名称（chrome、firefox、edge等）
    public static WebDriver initDriver(String browser) {
        try {
            if (driver == null) {
                switch (browser.toLowerCase()) {
                    case "chrome":
                        // 1. 配置 Chrome 专属参数
                        ChromeOptions chromeOptions = new ChromeOptions();
                        // 允许所有远程连接
                        chromeOptions.addArguments("--remote-allow-origins=*");

                        WebDriverManager.chromedriver().setup();
                        driver = new ChromeDriver(chromeOptions);
                        break;
                    case "firefox":
                        // 2. 配置 Firefox 专属参数（可扩展）
                        FirefoxOptions firefoxOptions = new FirefoxOptions();

                        WebDriverManager.firefoxdriver().setup();
                        driver = new FirefoxDriver(firefoxOptions);
                        break;
                    case "edge":
                        // 3. 配置 Edge 专属参数（可扩展）
                        EdgeOptions edgeOptions = new EdgeOptions();
                        edgeOptions.addArguments("--remote-allow-origins=*");

                        WebDriverManager.edgedriver().setup();
                        driver = new EdgeDriver(edgeOptions);
                        break;
                    default:
                        throw new IllegalArgumentException("不支持的浏览器类型:" + browser);
                }
                //设置浏览器窗口为最大化
                driver.manage().window().maximize();
                //设置隐式等待时间，全局等待元素加载,单位秒
                driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
                System.out.println(browser + "浏览器初始化成功!");
            }
            return driver;
        } catch (Exception e) {
            //1.打印详细堆栈信息
            e.printStackTrace();
            //2.抛出运行时异常
            throw new RuntimeException("浏览器初始化失败:" + e.getMessage(), e);
        }
    }

    //关闭浏览器驱动的方法
    public static void quitDriver() {
        if (driver != null) {
            driver.quit();
            driver = null; //重置为null，下次调用会重新初始化。
        }
    }

    //显式等待元素可见方法，传入元素定位器和超时时间(秒)
    public static WebElement waitForElementVisible(By locator, int timeout) {
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeout));
        return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
    }

    //显式等待元素可点击的方法，传入元素定位器和超时时间(秒)
    public static WebElement waitForElementClickable(By locator, int timeout) {
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeout));
        return wait.until(ExpectedConditions.elementToBeClickable(locator));
    }

    public static void getScreenShot(String str) throws IOException {
        SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS");

        String dirTime = sim1.format(System.currentTimeMillis());
        String fileTime = sim2.format(System.currentTimeMillis());

        String fileName = "./src/test/image/" + dirTime + "/" + str + "-" + fileTime + ".png";
        System.out.println("fileName:" + fileName);

        File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        //srcFile放到指定的位置
        FileUtils.copyFile(srcFile, new File(fileName));
    }
    /**
     * 智能滚动到目标元素，确保元素可见且可点击
     * @param element 目标元素
     * @param timeout 超时时间（秒）
     * @throws Exception 滚动失败时抛出异常
     */
    public static void smartScrollToElement(WebElement element, int timeout) throws Exception {
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeout));

        // 检查元素是否已在可视区域且可点击
        if (isElementVisibleAndClickable(element, wait)) {
            System.out.println("元素已可见且可点击，无需滚动");
            return;
        }

        // 方法1：使用JavaScript滚动到元素（定位到视口中央）
        try {
            // 执行滚动并将元素置于视口中央
            ((JavascriptExecutor) driver).executeScript(
                    "arguments[0].scrollIntoView({block: 'center', inline: 'nearest'});",
                    element
            );

            // 添加微小偏移（处理固定导航栏遮挡问题）
            ((JavascriptExecutor) driver).executeScript(
                    "window.scrollBy(0, -100);"  // 向上滚动100像素，避开顶部导航栏
            );

            // 等待页面稳定并检查元素状态
            Thread.sleep(300);

            if (isElementVisibleAndClickable(element, wait)) {
                element.click();
                System.out.println("使用JavaScript滚动到元素中央成功");
                return;
            }
        } catch (Exception e) {
            System.out.println("JavaScript滚动失败: " + e.getMessage());
        }

        // 方法2：使用组合滚动策略（针对复杂页面）
        try {
            Actions actions = new Actions(driver);
            int attempts = 0;

            while (attempts < 3) {
                // 向下滚动小步并检查
                actions.sendKeys(Keys.PAGE_DOWN).perform();
                Thread.sleep(200);

                if (isElementVisibleAndClickable(element, wait)) {
                    element.click();
                    System.out.println("使用组合滚动策略成功，尝试次数: " + (attempts + 1));
                    return;
                }

                attempts++;
            }
        } catch (Exception e) {
            System.out.println("组合滚动策略失败: " + e.getMessage());
        }

        // 方法3：处理元素被遮挡的情况
        try {
            // 检查元素是否被其他元素遮挡
            if (isElementObscured(element)) {
                System.out.println("元素被遮挡，尝试强制点击");

                // 使用JavaScript强制点击（绕过视觉遮挡）
                ((JavascriptExecutor) driver).executeScript(
                        "arguments[0].click();",
                        element
                );
                return;
            }
        } catch (Exception e) {
            System.out.println("强制点击失败: " + e.getMessage());
        }

        // 所有方法都失败
        throw new Exception("无法滚动到目标元素或元素不可点击");
    }

    /**
     * 检查元素是否可见且可点击
     */
    private static boolean isElementVisibleAndClickable(WebElement element, WebDriverWait wait) {
        try {
            // 检查元素是否可见
            wait.until(ExpectedConditions.visibilityOf(element));

            // 检查元素是否可点击
            wait.until(ExpectedConditions.elementToBeClickable(element));

            // 检查元素是否在视口内
            Boolean isInView = (Boolean) ((JavascriptExecutor) driver).executeScript(
                    "var rect = arguments[0].getBoundingClientRect();" +
                            "return (rect.top >= 0 && rect.bottom <= window.innerHeight && " +
                            "rect.left >= 0 && rect.right <= window.innerWidth);",
                    element
            );

            return isInView;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 检查元素是否被其他元素遮挡
     */
    private static boolean isElementObscured(WebElement element) {
        try {
            // 获取元素在页面中的位置
            Point location = element.getLocation();

            // 使用JavaScript检查元素顶部是否被其他元素覆盖
            Boolean isObscured = (Boolean) ((JavascriptExecutor) driver).executeScript(
                    "var element = arguments[0];" +
                            "var topElement = document.elementFromPoint(" +
                            location.getX() + ", " + location.getY() + ");" +
                            "return topElement !== element && !element.contains(topElement);",
                    element
            );

            return isObscured;
        } catch (Exception e) {
            return false;
        }
    }

    public static void pop(String expected,String message){
        // 添加等待弹窗出现的逻辑
        WebDriverWait pop = new WebDriverWait(driver, Duration.ofSeconds(10));
        Alert alert = pop.until(ExpectedConditions.alertIsPresent());

        // 处理弹窗
        String actualText = alert.getText();
        assertEquals(expected, actualText, message);
        alert.accept();
    }
    public static void pop(String expected,String message,boolean isFixOn){
        // 添加等待弹窗出现的逻辑
        WebDriverWait pop = new WebDriverWait(driver, Duration.ofSeconds(10));
        Alert alert = pop.until(ExpectedConditions.alertIsPresent());

        // 处理弹窗
        String actualText = alert.getText();
        assertEquals(expected, actualText, message);
        if (isFixOn){
            alert.accept();
        }else {
            alert.dismiss();
        }
    }
}
